package tc.alert.tckejisoc.task;


import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import tc.alert.tckejisoc.cache.CacheData;
import tc.alert.tckejisoc.domain.SocBanned;
import tc.alert.tckejisoc.domain.SocIp;
import tc.alert.tckejisoc.dto.Constants;
import tc.alert.tckejisoc.dto.EdrDTO;
import tc.alert.tckejisoc.kafka.service.KafkaProducerService;
import tc.alert.tckejisoc.service.GeoIPService;
import tc.alert.tckejisoc.service.SocBannedService;
import tc.alert.tckejisoc.service.SocIpService;
import tc.alert.tckejisoc.service.UserInfoService;
import tc.alert.tckejisoc.utils.DateUtils;
import tc.alert.tckejisoc.utils.EsUtils;

import java.io.IOException;
import java.time.Instant;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Component
@Slf4j
public class EsAlert {
    @Autowired
    private RestHighLevelClient client;
    @Autowired
    private KafkaProducerService kafkaProducerService;
    @Autowired
    private GeoIPService geoIPService;
    @Autowired
    private CacheData cacheData;
    @Autowired
    private UserInfoService userInfoService;
    @Autowired
    private SocBannedService socBannedService;
    @Autowired
    private SocIpService socIpService;
    @Autowired
    private RestTemplate esRestTemplate;

    @Scheduled(fixedRate = 3000)
    public Object test(){
//        String url = "http//192.168.11.2:9200" + "/";
//        ResponseEntity<Map> response = esRestTemplate.getForEntity(url, Map.class);
//        return response.getBody();
        log.debug("12312312312asd阿三大苏打实打实大苏打实打实3123123123");
        return null;
    }


//    @Scheduled(fixedRate = 3000)
//    public void ipzc() throws IOException {
//
//        String text = "阿达IP列表：阿斯顿192.168.1.1/2, /ase/qwe/10.0.0.256（无效）, qwe'255.255.255.255'";
//
//        // 严格匹配IPv4的正则表达式
//        String ipRegex =
//                "(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]\\d|\\d)\\." +
//                        "(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]\\d|\\d)\\." +
//                        "(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]\\d|\\d)\\." +
//                        "(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]\\d|\\d)";
//
//        Pattern pattern = Pattern.compile(ipRegex);
//        Matcher matcher = pattern.matcher(text);
//        List<String> ips = new ArrayList<>();
//
//        while (matcher.find()) {
//            ips.add(matcher.group());
//        }
//
//        System.out.println("提取到的IP地址：");
//        ips.forEach(System.out::println);
//
//    }
    /**
     * 获取索引
     *
     * @param // private Instant edrTime;
     *           <p>
     *           /**
     *           waf告警日志处理
     * @throws IOException
     */
//    @Scheduled(fixedRate = 30000)
    public void wafTask() throws IOException {
        log.info("处理waf预警");
        String getindex = EsUtils.getindex("waf-event-alert-");
        getindex = "waf-event-alert";
        if (!EsUtils.isIndexExists(client, getindex)) {
            return;
        }
        SearchResponse resp = searchAllDocuments(getindex, "waf-alert");
        if (null != resp) {
            List<EdrDTO> alertDTOS = EsUtils.regxWaf(client, resp.toString());

            for (EdrDTO dto : alertDTOS) {

                kafkaProducerService.sendMessage("waf-event-alert", JSON.toJSONString(dto));
//            insertIndex(dto);
                log.info("处理waf预警======>" + JSON.toJSONString(dto));
            }
        }
    }

    /**
     * 处理edr预警
     *
     * @throws IOException
     */
//    @Scheduled(fixedRate = 3000)
    public void edrTask() throws IOException {
        log.info("处理edr预警");
//        String getindex = getindex("edr-event-alert-");
        String getindex = "edr-event-alert";
        if (!EsUtils.isIndexExists(client, getindex)) {
            return;
        }
        SearchResponse resp = searchAllDocuments(getindex, "edr-alert");
        if (null != resp) {
            List<EdrDTO> alertDTOS = EsUtils.regxEdr(client, resp.toString());

            for (EdrDTO dto : alertDTOS) {

                kafkaProducerService.sendMessage("edr-event-alert", JSON.toJSONString(dto));
                log.info("处理edr预警======>" + JSON.toJSONString(dto));

            }
        }
    }

    /**
     * 处理天眼预警
     *
     * @throws IOException
     */
//    @Scheduled(fixedRate = 30000)
    public void tyTask() throws IOException {
        String getindex = EsUtils.getindex("ty-event-alert-");
        log.info("处理ty预警");
        getindex = "ty-event-alert";
        if (!EsUtils.isIndexExists(client, getindex)) {
            return;
        }
        SearchResponse resp = searchAllDocuments(getindex, "ty-alert");
        if (null != resp) {
            List<EdrDTO> alertDTOS = EsUtils.regxTy(client, resp.toString());

            for (EdrDTO dto : alertDTOS) {

                kafkaProducerService.sendMessage("ty-event-alert", JSON.toJSONString(dto));
//            insertIndex(dto);
                log.info("处理ty预警======>" + JSON.toJSONString(dto));
            }
        }
    }

    /**
     * 处理火绒预警
     *
     * @throws IOException
     */
//    @Scheduled(fixedRate = 30000)
    public void hrTask() throws IOException {
        String getindex = EsUtils.getindex("ty-event-alert-");
        log.info("处理hr预警");
        getindex = "hr-event-alert";
        if (!EsUtils.isIndexExists(client, getindex)) {
            return;
        }
        SearchResponse resp = searchAllDocuments(getindex, "hr-alert");
        if (null != resp) {
            List<EdrDTO> alertDTOS = EsUtils.regxHr(client, resp.toString());

            for (EdrDTO dto : alertDTOS) {

                kafkaProducerService.sendMessage("hr-event-alert", JSON.toJSONString(dto));
//            insertIndex(dto);
                log.info("处理hr预警======>" + JSON.toJSONString(dto));
            }
        }
    }


    //没5分钟查询索引下数据
//    @Scheduled(fixedRate = 60000 * 5)
    public void bannedIndexDataWaf() throws IOException {

        log.info("waf定时获取数据排查非国内ip");
        String getindex = EsUtils.getindex("event-waf-");
        SearchResponse s = searchAllDocuments(getindex.toString(), "wafTime");
        List<EdrDTO> srcIp = getIdsByIp(s, "src_ip", "event_id");
        if (null != srcIp) {
            SocIp qip = new SocIp();
            qip.setStatus(1);
            qip.setType(1);
//            List<SocIp> list = socIpService.selectListIp(qip);
            kafkasendmessage(srcIp, 1);
        }

    }

    //    @Scheduled(fixedRate = 60000 * 5)
    public void bannedIndexDataTy() throws IOException {
        log.info("ty定时获取数据排查非国内ip");
        String getindex = EsUtils.getindex("event-ty-");
        SearchResponse s = searchAllDocuments(getindex.toString(), "tyTime");
        List<EdrDTO> srcIp = getIdsByIp(s, "attack_sip", "_id");
        if (null != srcIp) {
            SocIp qip = new SocIp();
            qip.setStatus(1);
            qip.setType(3);
            //List<SocIp> list = socIpService.selectListIp(qip);
            kafkasendmessage(srcIp, 3);
        }

    }

    //    @Scheduled(fixedRate = 30000)
    public void bannedIndexDataEdr() throws IOException {
        String ip = "";
        log.info("edr定时获取数据排查非国内ip");
        String getindex = EsUtils.getindex("event-edr-");
        SearchResponse s = searchAllDocuments(getindex.toString(), "edrTime");
        List<EdrDTO> srcIp = getIdsByIp(s, "src_ip", "_id");
        if (null != srcIp) {
            SocIp qip = new SocIp();
            qip.setStatus(1);
            qip.setType(2);
//            List<SocIp> list = socIpService.selectListIp(qip);
            kafkasendmessage(srcIp, 2);
        }

    }

    public void kafkasendmessage(List<EdrDTO> srcIp, int type) {
        for (EdrDTO ipstr : srcIp) {
            String countryCode = geoIPService.getCountryCode(ipstr.getSrcIp());


            if (!countryCode.equals("CN") && !countryCode.equals("LAN")) {
                boolean b = checkIpBySql(ipstr.getSrcIp());
                if (!b) {
                    Object o = cacheData.get(ipstr.getSrcIp());
                    if (null == o) {
                        kafkaProducerService.sendMessage("waf-banned", JSON.toJSONString(ipstr));
                        log.info(type + "定时获取数据排查非国内ip======>" + JSON.toJSONString(ipstr));
                        insertSocBanned(ipstr, type);
                        cacheData.put(ipstr.getSrcIp(), ipstr.getSrcIp());
                    }

                }
            }
        }
    }

    public List<EdrDTO> getIdsByIp(SearchResponse resp, String key, String idkey) throws IOException {
        if (null != resp) {


            SearchHits hits = resp.getHits();
            List<EdrDTO> ids = new ArrayList<>();
            for (SearchHit hit : hits) {
                String index = hit.getIndex();
                String id = hit.getId();
                Map<String, Object> source = hit.getSourceAsMap();
                String ip = "";
                if (index.contains("ty")) {
                    Object attack = source.get("attack");
                    if (null != attack) {
                        Object sip = ((HashMap) attack).get("sip");
                        ip = sip.toString();

                    }
                } else {
                    ip = source.get(key) != null ? source.get(key).toString() : "";
                }
//                String id = source.get(idkey) != null ? source.get(idkey).toString() : "";
                if (StringUtils.isNoneBlank(ip)) {
                    EdrDTO dto = new EdrDTO();
                    dto.setSrcIp(ip);
                    dto.setIndex(index);
                    dto.setId(id);
                    ids.add(dto);

                }
            }
            return ids;
        }
        return null;
    }

    private SearchResponse searchAllDocuments(String index, String key) throws IOException {
        SearchRequest searchRequest = new SearchRequest(index);
        // 获取当前时间
        Instant now = Instant.now();
        Instant fiveMinutesAgo = null;


        Instant o = (Instant) cacheData.get(key);
        if (null != o) {
            fiveMinutesAgo = o;
        } else {
            fiveMinutesAgo = now.minusSeconds(50 * 60);
        }
        cacheData.put(key, now);
        Instant instant = (Instant) cacheData.get(key);


        // 计算5分钟前的时间


        // 构建范围查询
        RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("@timestamp").gte(fiveMinutesAgo)  // 大于等于5分钟前的时间
                .lte(now);
        // 构建SearchSourceBuilder
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(rangeQuery);
        searchRequest.source(sourceBuilder);
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        if (searchResponse == null) {
            return null;
        }
        if (searchResponse.getHits().getTotalHits().value == 0) {
            return null;
        }


        return searchResponse;
    }




    /**
     * true  存在白名单 false 不存在白名单
     *
     * @param ip
     * @return
     */
    public boolean checkIpBySql(String ip) {
        List<SocIp> list = new ArrayList<>();
        Object o = cacheData.get(Constants.SOCIP);
        //从缓存拿数据
        if (null != o) {
            list = (List<SocIp>) o;
        }
        boolean flag = false;

        for (SocIp socIp : list) {
            //判断ip是否是以段进行匹配    1 全量 2 范围
            if (socIp.getType() == 1) {
                if (socIp.getIp().equals(ip)) {
                    flag = true;
                } else {
                    String ipB = socIp.getIpB();
                    String ipE = socIp.getIpE();
                    if (StringUtils.isNoneBlank(ipB) && StringUtils.isNoneBlank(ipE)) {
                        flag = isIpInRange(ip, ipB, ipE);
                    }
                }
            }

        }


        return flag;
    }


    public static boolean isIpInRange(String targetIp, String startIp, String endIp) {
        long target = ipToLong(targetIp);
        long start = ipToLong(startIp);
        long end = ipToLong(endIp);

        long lower = Math.min(start, end);
        long upper = Math.max(start, end);

        return target >= lower && target <= upper;
    }

    private static long ipToLong(String ipAddress) {
        String[] octets = ipAddress.split("\\.");
        if (octets.length != 4) {
            throw new IllegalArgumentException("Invalid IP address format");
        }

        long result = 0;
        for (String octet : octets) {
            int value = Integer.parseInt(octet);
            if (value < 0 || value > 255) {
                throw new IllegalArgumentException("IP octet out of range");
            }
            result = (result << 8) | value;
        }
        return result;
    }


    public void insertSocBanned(List<EdrDTO> list, Integer type) {

        List<SocBanned> socBanneds = new ArrayList<>();
        for (EdrDTO socIp : list) {
            SocBanned socBanned = new SocBanned();
            socBanned.setIp(socIp.getSrcIp());
            socBanned.setCreateTime(DateUtils.format(new Date()));
            socBanned.setType(type);
            socBanned.setCreateUser("root");
            socBanned.setEventId(socIp.getId());
            socBanned.getBannedTime();
            socBanneds.add(socBanned);

        }

        if (!socBanneds.isEmpty()) {
            socBannedService.batchInsert(socBanneds);
        }
    }

    public void insertSocBanned(EdrDTO socIp, Integer type) {


        SocBanned socBanned = new SocBanned();
        socBanned.setIp(socIp.getSrcIp());
        socBanned.setCreateTime(DateUtils.format(new Date()));
        socBanned.setType(type);
        socBanned.setCreateUser("root");
        socBanned.setEventId(socIp.getId());
//            socBanned.setBannedTime(DateUtils.format(new Date()));


        socBannedService.insertSelective(socBanned);

    }
}
